﻿using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Drawing2D;

namespace FunDraw.usercontrols
{
    /// <summary>
    /// 坐标系类
    /// </summary>
    [ToolboxBitmap(typeof(Coordinate))]
    public partial class Coordinate : UserControl
    {
        #region 属性
        // 横坐标轴
        private Axis _AxisX = new Axis("X");

        // 纵坐标轴
        private Axis _AxisY = new Axis("Y");

        // 边界留白
        private int _bound = 10;

        //每单位像素点数
        private int _unit = 10;
        //标签的字体样式
        private Font _tagFont = new Font("Arial", 10F);
        // 光标信息颜色
        private Color _InfoColor = Color.Red;


        /// <summary>
        /// 坐标系中心点
        /// </summary>
        private PointF center = new PointF(0, 0);

        /// <summary>
        /// 背景网格线
        /// </summary>
        private Boolean _GridLine = false;

        /// <summary>
        /// 网格线颜色
        /// </summary>
        private Color _GridLineColor = Color.Gray;

        private int _GridUnit = 5;

        /// <summary>
        /// 是否显示象限标记
        /// </summary>
        private Boolean _showQuadrant;

        /// <summary>
        /// 显示象限标记
        /// </summary>
        [Category("Custom"), Description("是否显示象限标记")]
        public Boolean ShowQuadrant
        {
            get
            {
                return _showQuadrant;
            }
            set
            {
                _showQuadrant = value;
                Invalidate();
            }
        }


        public int GridUnit
        {
            get
            {
                return _GridUnit;
            }
            set
            {
                _GridUnit = value;
                Invalidate();
            }
        }
        /// <summary
        /// 是否显示网格线
        /// </summary>
        [Category("Custom"), Description("是否显示背景网格线")]
        public Boolean GridLine
        {
            get
            {
                return _GridLine;
            }
            set
            {
                _GridLine = value;
                Invalidate();
            }
        }
        /// <summary>
        /// 背景网格线的颜色
        /// </summary>
        [Category("Custom"), Description("背景网格线颜色")]
        public Color GridLineColor
        {
            get
            {
                return _GridLineColor;
            }
            set
            {
                _GridLineColor = value;
                Invalidate();
            }
        }

        /// <summary>
        /// 坐标系标记的字体样式
        /// </summary>
        [Category("Custom"), Description("坐标系标记字体样式")]
        public Font TagFont
        {
            get
            {
                return _tagFont;
            }
            set
            {
                _tagFont = value;
                Invalidate();
            }
        }


        /// <summary>
        /// 坐标轴的线条宽度，横纵相同默认为2
        /// </summary>
        [Category("Custom"), Description("坐标轴线条的宽度")]
        public int AxisLineWidth
        {
            get
            {
                return _AxisX.LineWidth;
            }
            set
            {
                _AxisX.LineWidth = value;
                _AxisY.LineWidth = value;
                 
                Invalidate();
            }
        }
        /// <summary>
        /// 坐标轴的线条宽度，横纵相同默认为2
        /// </summary>
        [Category("Custom"), Description("坐标轴线条颜色")]
        public Color AxisLineColor
        {
            get
            {
                return _AxisX.LineColor;
            }
            set
            {
                _AxisX.LineColor = value;
                _AxisY.LineColor = value;
                Invalidate();
            }
        }

        /// <summary>
        /// 边界留白外补丁
        /// </summary>
        [Category("Custom"), Description("坐标系周围的补丁")]
        public int Bound
        {
            get
            {
                return _bound;
            }
            set
            {
                _bound = value;
                Invalidate();
            }
        }

        /// <summary>
        /// 每单位的像素点数
        /// </summary>
        [Category("Custom"), Description("每单位所占像素数量")]
        public int Unit
        {
            get
            {
                return _unit;
            }
            set
            {
                _unit = value;
                Invalidate();
            }
        }


        /// <summary>
        /// 光标位置信息的颜色
        /// </summary>
        [Browsable(true)]
        [Category("Custom"), Description("光标位置信息颜色")]
        public Color InfoColor
        {
            get
            {
                return _InfoColor;
            }
            set
            {
                _InfoColor = value;
                Invalidate();
            }
        }
        #endregion
        /// <summary>
        /// 构造函数
        /// </summary>
        public Coordinate()
        {
            InitializeComponent();
            //this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.AllPaintingInWmPaint, true);
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.AllPaintingInWmPaint, true);
        }

        /// <summary>
        /// 绘制背景网格线
        /// </summary>
        private void PaintGridLine(Graphics g)
        {
            if (GridLine)
            {
                Pen pen = new Pen(_GridLineColor, 1);
                pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
                float maxY = (float)Math.Floor((double)Height / (Unit/2));
                float maxX = (float)Math.Floor((double)Width / (Unit/2));
                // 绘制横线
                for(float i=0;i<=Height;i=i+ _GridUnit)
                {
                    PointF startPoint = new PointF(0, i);
                    PointF endPoint = new PointF(Width, i);
                    g.DrawLine(pen, startPoint, endPoint);
                }
                // 绘制竖线
                for(float i=0;i<=Width; i = i + _GridUnit)
                {
                    PointF startPoint = new PointF(i, 0);
                    PointF endPoint = new PointF(i, Height);
                    g.DrawLine(pen, startPoint, endPoint);
                }
            }
        }

        /// <summary>
        /// 绘制函数
        /// </summary>
        /// <param name="pe"></param>
        protected override void OnPaint(PaintEventArgs pe)
        {
           
            GetCenter();
            Rectangle rect = pe.ClipRectangle;
            Bitmap bufferimage = new Bitmap(this.Width, this.Height);
            Graphics g = Graphics.FromImage(bufferimage);
            g.SmoothingMode = SmoothingMode.HighQuality; //高质量
            g.PixelOffsetMode = PixelOffsetMode.HighQuality; //高像素偏移质量
            int w = Width;
            int h = Height;
            lb_postion.ForeColor = _InfoColor;
            Pen gridPen = new Pen(GridLineColor);
            gridPen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;

           // PaintGridLine(g);

            #region 坐标系基本点位确定
            //横轴起点
            PointF x_start = new PointF(Bound, center.Y);
            //横轴终点
            PointF x_end = new PointF(w - Bound, center.Y);
            
            //纵轴终点
            PointF y_start = new PointF(center.X, h - Bound);
            //纵轴终点
            PointF y_end = new PointF(center.X, Bound);
            
            //横轴上箭头起点，终端为横轴终点
            PointF x_topArrowStart = new PointF(x_end.X- 10, x_end.Y - 10);
            //横轴下箭头起点，终点为横轴终点
            PointF x_bottomArrowStart = new PointF(x_end.X - 10, x_end.Y +10);
            
            //纵轴左箭头起点，终点为纵轴终点
            PointF y_leftArrowStart = new PointF(y_end.X - 10, y_end.Y + 10);
            //纵轴右箭头起点,终点为纵轴终点
            PointF y_rightArrowStart = new PointF(y_end.X + 10, y_end.Y + 10);
            #endregion

            #region 定义画刷及画笔
            Brush brush_tag = new SolidBrush(AxisLineColor);
            Pen axisPen = new Pen(AxisLineColor, AxisLineWidth);
            #endregion

            #region 绘制中心点标记
            PointF p_tagcenter = new PointF(center.X + 10, center.Y + 10);
            g.DrawString("0", TagFont, brush_tag, p_tagcenter);

            //绘制坐标轴
            g.DrawLine(axisPen, x_start, x_end);
            g.DrawLine(axisPen, y_start, y_end);
            g.DrawLine(axisPen, x_topArrowStart, x_end);
            g.DrawLine(axisPen, x_bottomArrowStart, x_end);
            g.DrawLine(axisPen, y_leftArrowStart, y_end);
            g.DrawLine(axisPen, y_rightArrowStart, y_end);

            PointF p_XaxisTag = new PointF(x_end.X-Bound, x_end.Y + Bound);
            PointF p_YaxisTag = new PointF(y_end.X + Bound, y_end.Y+Bound);
            g.DrawString(_AxisX.AxisName, TagFont, brush_tag, p_XaxisTag);
            g.DrawString(_AxisY.AxisName, TagFont, brush_tag, p_YaxisTag);
            #endregion

            #region 绘制x轴的刻度
            int xMax = (int)Math.Floor((double)(x_end.X - x_start.X) / (Unit*2))-1;
            _AxisX.Max = xMax;

            int yMax = (int)Math.Floor((double)(y_start.Y - y_end.Y) / (Unit * 2)) - 1;
            _AxisY.Max = yMax;

            for (int i=0;i<xMax;i++)
            {
                int index = i + 1;
                //正刻度
                PointF z_start = new PointF(center.X + index * Unit, center.Y);
                PointF z_end = new PointF(center.X + index * Unit, center.Y-4);
                PointF z_tag = new PointF(center.X + index * Unit + AxisLineWidth + 2, center.Y + AxisLineWidth + 2);
                g.DrawLine(axisPen, z_start, z_end);
                g.DrawString(index.ToString(), TagFont, brush_tag, z_tag);


                //负刻度
                PointF f_start = new PointF(center.X - index * Unit, center.Y);
                PointF f_end = new PointF(center.X - index * Unit, center.Y - 4);
                PointF f_tag = new PointF(center.X - index * Unit - AxisLineWidth - 2, center.Y + AxisLineWidth + 2);
                g.DrawLine(axisPen, f_start, f_end);
                g.DrawString((0-index).ToString(), TagFont, brush_tag, f_tag);

            }
            #endregion

            #region 绘制y轴的刻度

            for(int i=0;i<yMax;i++)
            {
                int index = i + 1;
   
                //正刻度
                PointF z_start = new PointF(center.X, center.Y-index*Unit);
                PointF z_end = new PointF(center.X+4, center.Y -index * Unit);
                PointF z_tag = new PointF(center.X + 4+2, center.Y -index * Unit);
                g.DrawLine(axisPen, z_start, z_end);
                g.DrawString(index.ToString(), TagFont, brush_tag, z_tag);


                //负刻度
                PointF f_start = new PointF(center.X, center.Y + index * Unit);
                PointF f_end = new PointF(center.X+4, center.Y + index * Unit);
                PointF f_tag = new PointF(center.X +4 + AxisLineWidth + 2, center.Y + index * Unit+2);
                g.DrawLine(axisPen, f_start, f_end);
                g.DrawString((0 - index).ToString(), TagFont, brush_tag, f_tag);
  
            }
            #endregion

            #region 绘制背景格
            if (_GridLine)
            {
                xMax = xMax + 2;
                yMax = yMax + 2;

                for(int i=0;i<xMax;i++)
                {
                    int idx = i + 1;
                    PointF s_start = new PointF(center.X+idx*Unit,y_start.Y);
                    PointF e_end = new PointF(center.X+idx * Unit, y_end.Y);
                    g.DrawLine(gridPen, s_start, e_end);
                    PointF fs_start = new PointF(center.X - idx * Unit,y_start.Y);
                    PointF fe_end = new PointF(center.X - idx * Unit, y_end.Y);
                    g.DrawLine(gridPen, fs_start, fe_end);
                }

                for(int i=0;i<yMax;i++)
                {
                    int idx = i + 1;
                    PointF s_start = new PointF(x_start.X, center.Y-idx*Unit);
                    PointF e_end = new PointF(x_end.X, center.Y-idx * Unit);
                    g.DrawLine(gridPen, s_start, e_end);
                    PointF fs_start = new PointF(x_start.X, center.Y+idx*Unit);
                    PointF fe_end = new PointF(x_end.X, center.Y+idx*Unit);
                    g.DrawLine(gridPen, fs_start, fe_end);
                }
            }
            #endregion

            #region 绘制象限标记
            if (_showQuadrant)
            {
                PointF firstPoint = new PointF(center.X + xMax / 2 * Unit, center.Y - yMax / 2 * Unit);
                g.DrawString("第一象限\r\n(X>0,Y>0)", TagFont, brush_tag, firstPoint);

                PointF secondPoint = new PointF(center.X - xMax / 2 * Unit, center.Y - yMax / 2 * Unit);
                g.DrawString("第二象限\r\n(X<0,Y>0)", TagFont, brush_tag, secondPoint);

                PointF thirdPoint = new PointF(center.X - xMax / 2 * Unit, center.Y + yMax / 2 * Unit);
                g.DrawString("第三象限\r\n(X<0,Y<0)", TagFont, brush_tag, thirdPoint);

                PointF fourthPoint = new PointF(center.X + xMax / 2 * Unit, center.Y + yMax / 2 * Unit);
                g.DrawString("第四象限\r\n(X>0,Y<0)", TagFont, brush_tag, fourthPoint);
            }
            #endregion
            pe.Graphics.DrawImage(bufferimage, 0, 0);
            gridPen.Dispose();
            axisPen.Dispose();
            base.OnPaint(pe);
        }

        /// <summary>
        /// 获取坐标系中心点
        /// </summary>
        public void GetCenter()
        {
            center = new PointF(Width / 2, Height / 2);
        }
        /// <summary>
        /// 更新鼠标位置信息
        /// </summary>
        /// <param name="p"></param>
        public void UpdateMousePostion(Point p)
        {
            double x_val = Math.Round((p.X - center.X) / (double)Unit, 1);
            double y_val = Math.Round((center.Y - p.Y) / (double)Unit, 1);
            string info = string.Format("[X:{0},Y:{1}]", x_val.ToString(), y_val.ToString());
            lb_postion.Text = info;
        }

        /// <summary>
        /// 鼠标移动事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Coordinate_MouseMove(object sender, MouseEventArgs e)
        {
            double x_val = Math.Round((e.X - center.X)/(double)Unit,1);
            double y_val = Math.Round((center.Y - e.Y)/(double)Unit,1);
            string info = string.Format("[X:{0},Y:{1}]", x_val.ToString(), y_val.ToString());
            lb_postion.Text = info;
        }
    }
}
